﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.Extensions.FileSystemGlobbing.Internal;

namespace Qianke.Core.Common
{

    /// <summary>
    /// 脚本替换
    /// </summary>
    public class ScriptReplace
    {

        /// <summary>
        /// 替换脚本里的标签
        /// </summary>
        /// <param name="paramScript"></param>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static string ReplaceParamScript(string paramScript, Dictionary<string, Func<string, object>> dict)
        {
            //正则替换
            var pattern = string.Join("|", (dict.Keys as IEnumerable<string>).Select(n => $"\\[{n}\\]"));
            var strBody = Regex.Replace(paramScript, @"\[[^\[]*?\]", m =>
            {
                var keyName = m.Value;
                keyName = keyName.Substring(1, keyName.Length - 2); //去中括号
                object result = null;
                var nIndex = keyName.IndexOf(':');
                if (nIndex >= 0)
                {
                    //有参数
                    var action = keyName.Substring(0, nIndex);
                    var param = keyName.Substring(nIndex + 1);
                    if (!dict.ContainsKey(action))
                        return m.Value;
                    result = dict[action].Invoke(param);
                }
                else
                {
                    if (!dict.ContainsKey(keyName))
                        return m.Value;
                    result = dict[keyName].Invoke("");
                }
                if (result == null) return string.Empty;

                if (result is Task)
                    try
                    {
                        return result.Get("Result")?.ToString();
                    }
                    catch (Exception ex)
                    {
                        return keyName;
                    }
                return result.ToString();
            });
            return strBody;
        }


        public static string ReplaceParamScript(string paramScript, Dictionary<string, object> dict)
        {
            //正则替换
            var pattern = string.Join("|", (dict.Keys as IEnumerable<string>).Select(n => $"\\[{n}\\]"));
            var strBody = Regex.Replace(paramScript, @"\[[^\[]*?\]", m =>
            {
                var keyName = m.Value;
                keyName = keyName.Substring(1, keyName.Length - 2); //去中括号
                object result = null;
                var nIndex = keyName.IndexOf(':');
                if (nIndex >= 0)
                {
                    //有参数
                    var action = keyName.Substring(0, nIndex);
                    var param = keyName.Substring(nIndex + 1);
                    if (!dict.ContainsKey(action))
                        return m.Value ?? "";
                    result = dict[action];
                }
                else
                {
                    if (!dict.ContainsKey(keyName))
                        return m.Value ?? "";
                    result = dict[keyName];
                }
                if (result == null) return string.Empty;

                var taskResult = result as Task<object>;
                if (taskResult != null)
                    result = taskResult.Result;
                return result.ToString();
            });
            return strBody;
        }


        /// <summary>
        /// 替换且执行脚本里的Lua代码
        /// </summary>
        /// <param name="paramScript"></param>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static async Task<string> HandleParamScript(string paramScript, Dictionary<string, Func<string, object>> dict)
        {
            var strBody = ReplaceParamScript(paramScript, dict);
            //动态CS代码执行
            if (strBody.IndexOf("<#") >= 0)
                strBody = await GenerateExecutableCSharpScript(strBody);
            return strBody;
        }

        /// <summary>
        /// 替换且执行脚本里的Lua代码
        /// </summary>
        /// <param name="paramScript"></param>
        /// <param name="dict"></param>
        /// <returns></returns>
        public static async Task<string> HandleParamScript(string paramScript, Dictionary<string, object> dict)
        {
            var strBody = ReplaceParamScript(paramScript, dict);
            //动态CS代码执行
            if (strBody.IndexOf("<#") >= 0)
                strBody = await GenerateExecutableCSharpScript(strBody);
            return strBody;
        }


        public static async Task<string> GenerateExecutableCSharpScript(string scriptContext)
        {
            //脚本加工
            var strBuilder = new StringBuilder();
            strBuilder.AppendLine("string strResult = \"\";");
            var scriptLength = scriptContext.Length;
            var cach = new StringBuilder();
            var curType = 0;// 0脚本  1变量  2代码段  3字符串
            for (int i = 0; i < scriptLength; i++)
            {
                var ch = scriptContext[i];
                switch (ch)
                {
                    case '<':
                        if (curType == 0 && scriptContext[i + 1] == '#')
                        {
                            //说明有C# 代码或者 变量插入
                            //先把之前的内容写入
                            strBuilder.AppendLine($"strResult = strResult + \"{cach.ToString()}\";");
                            cach.Clear();
                            if (scriptContext[i + 2] == '=')
                            {
                                curType = 1;
                                i += 2;
                            }
                            else
                            {
                                curType = 2;
                                i += 1;
                            }

                        }
                        else
                            cach.Append(ch);
                        break;
                    case '#':
                        if ((curType == 1 || curType == 2) && scriptContext[i + 1] == '>')
                        {
                            if (curType == 1)
                            {
                                //变量统计结束了；
                                strBuilder.AppendLine($"strResult= strResult+({cach.ToString()});");
                                cach.Clear();
                                curType = 0;
                                i++;
                            }
                            else if (curType == 2)
                            {
                                //代码段结束
                                strBuilder.AppendLine(cach.ToString());
                                cach.Clear();
                                curType = 0;
                                i++;
                            }
                        }
                        else
                            cach.Append(ch);
                        break;
                    case '\"':
                        if (curType == 0)
                            cach.Append("\\\"");
                        else
                            cach.Append(ch);
                        break;
                    case '\r':
                        if (curType == 0)
                            cach.Append("\\r");
                        else
                            cach.Append(ch);
                        break;
                    case '\n':
                        if (curType == 0)
                            cach.Append("\\n");
                        else
                            cach.Append(ch);
                        break;
                    default:
                        cach.Append(ch);
                        break;
                }
            }
            strBuilder.AppendLine($"strResult= strResult+\"{cach.ToString()}\";");//最后一段也要加进来
            strBuilder.AppendLine("return strResult;");
            var strScript = strBuilder.ToString();
            return await CSharpScript.EvaluateAsync(strScript) as string;
        }





        public string Run()
        {
            //string result = Regex.Replace("template", "pattern", async match =>
            //{
            //    var expression = match.Groups[1].Value;
            //    var tresult = await CSharpScript.EvaluateAsync(expression);
            //    return tresult.ToString();
            //});


            return "";
        }
    }
}
